/***********************************************************************
* ******************************************************************** *
* *																					 	* *		
* *	Universal BIOS for Z-World/Rabbit Semiconductor Rabbit 2000    * *		
* *	CPU based boards.                                              * *		
* *																						* *		
* * 	Copyright (c)  1999-2002 Z-World.                              * *		
* *																						* *							
* *	Assumes ATMEL compatible flash algorithms                      * *		
* *                                                                  * *						
* *******************************************************************  *
************************************************************************/

#ifndef __BIOS_ALREADY_COMPILED
	#define __BIOS_ALREADY_COMPILED
#else
	#fatal "Cannot compile the BIOS as a user program!"
#endif

/////// BEGIN USER MODIFIABLE MACROS /////////////////////////////////

//***** Miscellaneous Information *******************************************
#define PRODUCT_NAME	"Universal Rabbit BIOS Version 7.25"	

#define CLOCK_DOUBLED  1			// Set to 1 to double clock if
											//		Rabbit 2000:	crystal <= 12.9024 MHz,
											//		Rabbit 3000:	crystal <= 26.4192 MHz,
											//  or to 0 to always disable clock doubler

#define CS1_ALWAYS_ON  0         // Keeping CS1 active is useful if your
                                 // system is pushing the limits of RAM
                                 // access time. It will increase power
                                 // consumption a little. Set to 0 to
                                 // disable, 1 to enable

//***** Clock Modulator Information ***************************************
#define ENABLE_SPREADER	1			// Set to 0 to disable spectrum spreader,
											// 1 to enable normal spreading, or
											// 2 to to enable strong spreading.

//***** File System Information *******************************************
#define XMEM_RESERVE_SIZE 0x0000L // Amount of space in the first flash to
                                 //  reserve. Dynamic C will not use this
                                 //  much flash for xmemory code space.
                                 //  This allows the filesystem to be used on
                                 //  the first flash.

#define FS2_RAM_RESERVE 0			//  Number of 4096-byte blocks to reserve for
											//  filesystem II battery-backed RAM extent.
											//  Leave this at zero if not using RAM filesystem.

//******* Target communication configuration ********************************
#define TC_SYSBUF_SIZE		256	// The size of the internal target communication
											// system buffers. The TC_HEADER_RESERVE size is
											// included in this value, so adjust the size of
											// the buffer accordingly.

#define TC_SYSBUF_COUNT		15		// The number of internal target communication
											// system buffers. Each is of the size
											// TC_SYSBUF_SIZE, as defined above.

#define TC_WRITEBLOCK_SIZE	256	// The size of the buffer that WriteBlocks are
											// received into, and therefor the MTU of a
											// write request.
                                             											
//***** Error Logging information *******************************************
//   Extend RAM for the error logging is pre-allocated in chunks of 4096.
//   The default configuration (when ENABLE_ERROR_LOGGING is 1) uses
//   one 4096 chunk.      
#define ENABLE_ERROR_LOGGING   0 // Enable error logging, set to 1 to enable
#define ERRLOG_USE_REG_DUMP    1 //  Include register dump in log entries
#define ERRLOG_STACKDUMP_SIZE 16 //  Include stack dump of this size in entries
#define ERRLOG_USE_MESSAGE     0 // Use this to include an 8 byte message in the
                                 //  log entries. The default exception handler
                                 //  currently makes no use of this.

#define ERRLOG_NUM_ENTRIES    78 // For best use of RAM space, choose a value that
                                 //  that will make a log size close to a multiple
                                 //  of 4096 
#ifdef _RAM_
#if (ENABLE_ERROR_LOGGING==1)
#error "Error logging not available when compiling to RAM"
#undef ENABLE_ERROR_LOGGING
#define ENABLE_ERROR_LOGGING 0
#endif
#endif

/***** Cloning Information *******************************************
 When after cloning starts, the LED on the cloning board goes out.
 It begins toggling about every second after the initial loaders 
 are transfered and running.
 When cloning is finished, the LED stays on. If any error occurs
 while cloning the LED will start blinking. Possible errors are
 autobaud failed, flash write failed, checksum incorrect.
**********************************************************************/

#define ENABLE_CLONING         0 // Set to 1 to enable cloning.

#define CL_CHECKSUM_ENABLED    1 // Do Internet checksum for cloning.
                                 //  Setting this to 0 will save some code
                                 //  size and a little time. Uses RFC 1071,
                                 //  1624 method.

#define CL_ASSUME_SAME_CRYSTAL 0 // 0 Assumes crystal speed is different on master
                                 //  and slave. Setting to 1 saves code space
                                 //  for the crystal speed measurement and
                                 //  autobauding. Autobauding works by setting
                                 //  the slave and master to the highest baud
                                 //  rate possible, and lowering the master's
                                 //  baud rate until they match. This MUST be 
                                 //  set to 0 if the slave's crystal is or 
                                 //  might be slower than the master's. If this is 
                                 //  set to 1, make sure CL_DOUBLE_CLONE_CLOCK and 
                                 //  CLOCK_DOUBLED are set the same if copying
                                 //  to like speed boards, since no autobauding
                                 //  will take place.

#define STERILE_CLONES         0 // Seeting to 1 causes cloned boards to bypass 
                                 //  the check for the cloning cable, thereby 
                                 //  disabling cloning of clones

#define CL_RUN_AFTER_COPYING   1 // Set to 0 to not run program on slave after
                                 //  cloning.

#define CLONE_WHOLE_FLASH	    0 // Set to 1 to copy entire flash device to
                                 //  excludes system ID block unless 
                                 //  CL_INCLUDE_ID_BLOCKS is set to 1 also.
                                 //  Excludes secondary flash device, but
                                 //  but if the program being cloned extends
                                 //  into the second flash, it will be copied
                                 //  regardless of this setting.
                                 
#define CL_COPY_2NDFLASH       0 // Set to 1 to clone second flash also. This
                                 //  is separate from USE_2NDFLASH_CODE so that
                                 //  files in the 2nd flash can be copied too if
                                 //  desired. This will cause the second flash
                                 //  to be copied unconditionally even if the
                                 //  the program doesn't span two flashes.
                                                                  
#define CL_INCLUDE_ID_BLOCKS   0 // Set to 1 to copy system ID and user block
                                 //  areas when cloning. Setting this to 1 will
                                 //  cause the ID blocks to be copied
                                 //  unconditionally.

#define CL_DOUBLE_CLONE_CLOCK  0 // If the cloned board has or might have a 
                                 //  crystal speed more than 12.9MHz, this 
                                 //  be MUST be set to 0. This macro is
                                 //  independent of the CLOCK_DOUBLED macro. It
                                 //  only applies clock doubling WHILE cloning.

#define INITIAL_SLV_BAUD_DIV   0 // If the slave is faster than, or might be
                                 //  faster than the master, increase this to
                                 //  the value needed to to achieve the fastest
                                 //  common baud rate that works on both boards.
                                 //  0 will always work when the slave crystal
                                 //  speed is equal to the master crystal speed.
                                 //  (This is the value that goes in the divisor
                                 //  register, the actual divisor is this plus 1.)
											//  The divisor register value is determined as
											//  follows:			
                                 //  divisor reg. value = (crystal frequency in Hz) 
                                 //                        -----------------------  - 1
                                 //                           (32 * baud rate) 
                                 //  For achievable baud rates, this should within
                                 //  4% of an integral value.
											//			
                                 //  Max baud rate = (crystal frequency in Hz) /32
                                 //
                                 //  If CL_DOUBLE_CLONE_CLOCK = 1, the crystal
                                 //  frequency is the double the crystal frequency.
                                 //
                                 //  Use this macro also if mismatched crystal speeds
                                 //  will prevent the master from achieving a common
                                 //  baud rate with the slave if the slave's div. reg.
                                 //  is 0. For example, set to 4 if the master is 12.8MHz
                                 //  and the slave is 9.2MHz. 
                                                                  
#if (ENABLE_CLONING == 1)
	#ifdef _RAM_
		#error "Cannot enbale cloning when compiling to RAM."
		#undef ENABLE_CLONING
		#define ENABLE_CLONING 0
	#endif
#endif

//***** Memory mapping information ************************************
//#define USE_2NDFLASH_CODE      // Uncomment this only if you have a
                                 //  a board with 2 256K flashes, and you
                                 //  want to use the second flash for extra
                                 //  code space. The file system is not
                                 //  compatible with using the second flash
                                 //  for code.

#define DATAORG      0x6000      // Begining logical address for data seg.
                                 // A user with a lot of root code
                                 // and not alot of root data can increase
                                 // this in increments of 0x1000 to as high
                                 // as 0xB000 to allow more root code space.
                                 // OR, root data space can be increased by
                                 // lowering this to as low as 0x3000.

#if (_RAM_SIZE_==0x80)           // Number of 4k pages of RAM. _RAM_SIZE_  
#define RAM_SIZE 0x40            // is defined internally by Dynamic C
#else										// during the coldboot stage, but can
#define RAM_SIZE _RAM_SIZE_      // changed here. If _RAM_SIZE_ is 0x80 (512K)
#endif                           // we reserve the upper half for xalloc
                                 // and map top of DATA to the top of the
                                 // lower half of RAM. The xalloc initialization
                                 // code will recognize that the space is
                                 // available if RAM_SIZE < _RAM_SIZE_.

#define FLASH_SIZE _FLASH_SIZE_  // Number of 4k pages of flash. _FLASH_SIZE_  
                                 // is defined internally by Dynamic C during
                                 // the coldboot stage by reading the flash ID
                                 // int from the flash on CS0, but can be changed
			          				   // here.

#define WATCHCODESIZE    0x200   // Number of root RAM bytes for Watch Code

//***** Debug Kernel Information ******************************************
											// _DK_ENABLE_BREAKPOINTS_ is defined internally
											// by Dynamic C and is set to 1 to enable
											// breakpoint support in debug kernel, 0 to
											// disable support and reclaim code space
#define DK_ENABLE_BREAKPOINTS			_DK_ENABLE_BREAKPOINTS_			
																						
											// _DK_ENABLE_ASMSINGLESTEP_ is defined
											// internally by Dynamic C and is set to 1
											// to enable assembly level single step
											// support in the debug kernel, 0 to
											// disable support and reclaim code space
#define DK_ENABLE_ASMSINGLESTEP		_DK_ENABLE_ASMSINGLESTEP_		

											// _DK_ENABLE_WATCHEXPRESSIONS_ is defined
											// internally by Dynamic C and is set to 1
											// to enable watch expressions in the debug
											// kernel, 0 to disable support and reclaim
											// code space
#define DK_ENABLE_WATCHEXPRESSIONS	_DK_ENABLE_WATCHEXPRESSIONS_	

//********************************************************************
//  Advanced configuration items follow
//  (Primarily of interest to board makers)
//********************************************************************

#define MAX_USERBLOCK_SIZE 0x8000 // This amount of flash gets excluded from
                                  // the available code space for the user
                                  // block and system ID areas. This could
                                  // be reduced to as little 0x1000, but
                                  // future binary compatibility with large
                                  // sector flash types will be compromised
                                  // for programs that use writeUserBlock()
                                  // readUserBlock(). This should be a
                                  // multiple of 0x1000

//***** Starting 4k page for RAM physical addresses *******************
#ifdef _FLASH_
#define RAM_START       0x80     // RAM normally starts at 0x80000
#else          
#define RAM_START       0x0      //	RAM starts at 00000 if compiling to RAM 
#endif 

//***** Wait States for the memory devices ****************************
#define NUM_RAM_WAITST	 0       
#define NUM_FLASH_WAITST 0
#define NUM_CS2_WAITST   0

//***** Chip selects/write enables for the memory devices *************
#define CS_FLASH			0x00    // CS0/OE0/WE0   
#define CS_RAM				0x05	  // CS1/OE1/WE1	
#define CS_FLASH2			0x02    // CS2/OE0/WE0

//***** Inversion bits for bank control registers *********************
#define MB0CR_INVRT_A18  0
#define MB1CR_INVRT_A18  0
#define MB2CR_INVRT_A18  0
#define MB3CR_INVRT_A18  0
#define MB0CR_INVRT_A19  0
#define MB1CR_INVRT_A19  0
#define MB2CR_INVRT_A19  0
#define MB3CR_INVRT_A19  0

////////// END OF USER-MODIFIABLE MACROS /////////////////////////////////
#if (MAX_USERBLOCK_SIZE&0x0fff)
   #error "MAX_USERBLOCK_SIZE must multiple of 0x1000" 
#endif
#if (MAX_USERBLOCK_SIZE<0x2000)
   #error "MAX_USERBLOCK_SIZE must at least 0x1000" 
#endif

//**** These are redefinitions which are done if the macro 
//****  COMPILE_SECONDARY_PROG is defined. These cause the RAM 
//****  to be split, and the top half used, and they map
//****  quadrant 0 to  CS2/OE0/WE0. This for situations where 2
//****  co-resident programs are used ONLY, such as a downloader 
//****  and a downloaded program. The downloaded program should
//****  generally be the secondary program. 
#ifdef  COMPILE_SECONDARY_PROG
	#ifdef _RAM_
		#error "Intended for DOWN_LOAD sample only.  Please undefine COMPILE_SECONDARY_PROG."
	#endif
	#undef  RAM_SIZE
   #undef  CS_FLASH
	#ifdef  INVERT_A18_ON_PRIMARY_FLASH
		#undef  MB1CR_INVRT_A18
		#define MB1CR_INVRT_A18  1
   #endif		
   #define CS_FLASH	0x02    
   #if (_RAM_SIZE_==0x80)
	   #undef _RAM_SIZE_
      #define _RAM_SIZE_ 0x40
   #else
      #if (_RAM_SIZE_==0x40)
		   #undef _RAM_SIZE_
 	      #define _RAM_SIZE_ 0x20
      #else
         #if (_RAM_SIZE_==0x20)
 	         #undef _RAM_SIZE_
		      #define _RAM_SIZE_ 0x10
         #else
            #error "unknown RAM size" 
         #endif
	  #endif
   #endif
   #undef  RAM_START
   #define RAM_SIZE _RAM_SIZE_
   #define RAM_START 0x80+RAM_SIZE
#endif

//**** These are redefinitions which are done if the macro 
//****  COMPILE_PRIMARY_PROG is defined. These cause the RAM 
//****  to be split, and the bottom half used. This for situations 
//****  where 2 co-resident programs are used ONLY, such as a downloader
//****  and a downloaded program. The downloader program should
//****  generally be the primary program. 
#ifdef  COMPILE_PRIMARY_PROG
	#ifdef _RAM_
		#error "Intended for DOWN_LOAD sample only.  Please undefine COMPILE_PRIMARY_PROG."
	#endif
	#if (_RAM_SIZE_==0x80)
	   #undef _RAM_SIZE_
      #define _RAM_SIZE_ 0x40
   #else
      #if (_RAM_SIZE_==0x40)
	 	   #undef _RAM_SIZE_
   	   #define _RAM_SIZE_ 0x20
      #else
         #if (_RAM_SIZE_==0x20)
   			#undef _RAM_SIZE_
	         #define _RAM_SIZE_ 0x10
		   #else
   	      #error "Unknown RAM size" 
         #endif
      #endif
   #endif
   #undef RAM_SIZE
   #define RAM_SIZE _RAM_SIZE_
#endif

struct _regBuffer {
	unsigned _AF;
	unsigned _BC;
	unsigned _DE;
	unsigned _HL;
	unsigned _SP;
	unsigned _PC;
	unsigned _XPC;
	unsigned _IX;
	unsigned _IY;
	unsigned _AFprime;
	unsigned _BCprime;
	unsigned _DEprime;
	unsigned _HLprime;	
};


typedef struct {
	unsigned short addr;  // address
	unsigned char base;   // base (BBR or CBR)
}	ADDR24_S;

typedef union { unsigned long l;    // long for increment/decrement 
					struct { ADDR24_S a; // the address itself 
								char flags; // flags associated 
						 } aaa;
}	ADDR24;

typedef struct
{
	unsigned    char  Size;
	unsigned    char  Type;
	unsigned    long  Mods;
} TypedInfo;

typedef union
{
	unsigned short  Integer;
	unsigned long   Long;
	float           Float;
	ADDR24          Addr;
} TypedValue;

typedef struct
{
	TypedInfo       TypedData;
	TypedValue      Value;  // value pushed without padding
} TypedArg;

struct _errLogEntry
{
	long   secTimer;
	ADDR24 address;
	char   errType;
#if (ERRLOG_USE_MESSAGE==1)
	char   message[8];
#endif
#if (ERRLOG_USE_REG_DUMP==1)
	struct _regBuffer regDump;
#endif
#if (ERRLOG_STACKDUMP_SIZE!=0)
	char stackDump[ERRLOG_STACKDUMP_SIZE];
#endif
	char  checksum; 
};

struct _errLogInfo
{
	char     status;
	unsigned ExceptionIndex;
	unsigned ExceptionIndexMod;
	unsigned errorsSinceDeployment;
	unsigned HWresetsSinceDeployment;
	unsigned WDTOsSinceDeployment;
	unsigned SWresetsSinceDeployment;
	char     headerChecksum;
};

#if (ENABLE_ERROR_LOGGING==1)
#define ERRLOG_LOG_SIZE (ERRLOG_NUM_ENTRIES*sizeof(struct _errLogEntry)+sizeof(struct _errLogInfo))
#if (0x10000ul <= ERRLOG_LOG_SIZE)
#error "Error log size too big"
#endif
#else
#define ERRLOG_LOG_SIZE 0
#endif 

#if (ENABLE_ERROR_LOGGING==1)
#define ERRLOG_NBLOCKS (1+ERRLOG_LOG_SIZE/4096)
#else
#define ERRLOG_NBLOCKS 0
#endif

#if ((_BIOSBAUD_ !=  9600) && (_BIOSBAUD_ != 19200) && \
     (_BIOSBAUD_ != 38400) && (_BIOSBAUD_ != 57600) && \
     (_BIOSBAUD_ != 115200))
#error "Unsupported BIOS comm baud rate:  choose 9600, 19200, 38400, 57600, or 115200."
#endif

//***** Settings for bank control registers ***************************
#ifdef _FLASH_		// running in flash
  #define MB0CR_SETTING	FLASH_WSTATES | CS_FLASH  | (MB0CR_INVRT_A18<<4) | (MB0CR_INVRT_A19<<5)
  #if (_FLASH_SIZE_ == 0x80)
    #define MB1CR_SETTING	FLASH_WSTATES | CS_FLASH  | (MB1CR_INVRT_A18<<4) | (MB1CR_INVRT_A19<<5)
  #else
    #define MB1CR_SETTING	FLASH_WSTATES | CS_FLASH2 | (MB1CR_INVRT_A18<<4) | (MB1CR_INVRT_A19<<5)
  #endif

#define MB2CR_SETTING	RAM_WSTATES | CS_RAM | (MB2CR_INVRT_A18<<4) | (MB2CR_INVRT_A19<<5)
#define MB3CR_SETTING	RAM_WSTATES | CS_RAM | (MB3CR_INVRT_A18<<4) | (MB3CR_INVRT_A19<<5)

#else  // running in RAM
#define MB0CR_SETTING	RAM_WSTATES | CS_RAM | (MB0CR_INVRT_A18<<4) | (MB0CR_INVRT_A19<<5)
#define MB1CR_SETTING	RAM_WSTATES | CS_RAM | (MB1CR_INVRT_A18<<4) | (MB1CR_INVRT_A19<<5)
#define MB2CR_SETTING	RAM_WSTATES | CS_RAM | (MB2CR_INVRT_A18<<4) | (MB2CR_INVRT_A19<<5)
#define MB3CR_SETTING	RAM_WSTATES | CS_RAM | (MB3CR_INVRT_A18<<4) | (MB3CR_INVRT_A19<<5)
#endif

#define STACKORG  		0xD000	// Begining logical address for stack segment

/* size of the block reserved for the TC system buffers */
#define TC_SYSBUF_BLOCK	(((long)TC_SYSBUF_SIZE*(long)TC_SYSBUF_COUNT)+(long)TC_WRITEBLOCK_SIZE)
#define TC_SYSBUF_BLOCK4K	1

//***** Compute the MMU segment registers *****
//***** the 1 represents space for a 4K flash transfer buffer
#define DATASEGVAL   RAM_START + RAM_SIZE - (STACKORG>>12) - (1+ERRLOG_NBLOCKS+FS2_RAM_RESERVE)-TC_SYSBUF_BLOCK4K

#define XMEMSEGVAL	(0xff & ((DATAORG-0xe000)/4096))

#ifdef USE_2NDFLASH_CODE
	#ifdef _RAM_
	#undef USE_2NDFLASH_CODE
	#warnt "USE_2NDFLASH_CODE disabled when compiling to RAM."
	#endif
#endif

#ifdef USE_2NDFLASH_CODE
#define XMEMSEGVAL2 	(0xff & ((-0xE000)/4096 + FLASH_SIZE))
#endif

#define MEMBREAK    0+(STACKORG/256) + (DATAORG/4096)  // SEGSIZE reg value


//***** Compute Code and Data ORGs ************************************
#ifndef FS_RESERVE_SIZE
#define FS_RESERVE_SIZE 0	// default to no space reserved for the FS in the first flash
#endif
#define WATCHCODEORG 	STACKORG-(0x0200+WATCHCODESIZE)
#define ROOTCODEORG  	0x0000
#define XMEMORYORG   	0xE000

#ifdef _FLASH_
#ifdef USE_2NDFLASH_CODE
#define XMEMORYSIZE2		FLASH_SIZE*4096L
#endif
#define XMEMORYSIZE   	FLASH_SIZE*4096L-DATAORG-MAX_USERBLOCK_SIZE-XMEM_RESERVE_SIZE
#endif

#ifdef _RAM_
#define XMEMORYSIZE   	RAM_SIZE*4096L-0xE000-FS2_RAM_RESERVE*4096L-TC_SYSBUF_BLOCK
#endif

#define ROOTCODESIZE  	DATAORG   
#define ROOTDATAORG  	WATCHCODEORG-0x0001
#define ROOTDATASIZE  	STACKORG-(DATAORG+0x200+WATCHCODESIZE)

/* marker for where the end of XMEM is */
#define END_OF_XMEMORY	(((XMEMSEGVAL<<12L)+(long)XMEMORYORG+(long)XMEMORYSIZE)&0xFFFFF)

//***** This is to let Dynamic C programs know we are running in Flash or RAM.
//***** _RAM_, and _FLASH_ are defined by the compiler.  RUN_IN_RAM
//***** predates these compiler generated macros.
#ifdef _FLASH_
#define RUN_IN_RAM 0					
#else
#define RUN_IN_RAM 1
#endif

//***** Tell the compiler this is a BIOS 
#pragma Rabbit CompileBIOS 	

#ifdef USE_2NDFLASH_CODE
#if FS_RESERVE_SIZE > 0
#error "Using second flash for both code and a filesystem is not currently supported."
#endif
#endif

/*-------------------------------------------------------------------
**  CODE ORG statements to determine code locations in physical and
**  logical memory space.
**
**  Type Name     Segment       Bottom       Size			  	   Use
--------------------------------------------------------------------*/
#rcodorg rootcode	0x00          ROOTCODEORG  ROOTCODESIZE		apply


#ifdef USE_2NDFLASH_CODE
#xcodorg xmemcode (XMEMSEGVAL)  XMEMORYORG	XMEMORYSIZE			apply
#xcodorg xmemcod2 (XMEMSEGVAL2) XMEMORYORG 	XMEMORYSIZE2 		follows xmemcode splitbin
#else
#xcodorg xmemcode	(XMEMSEGVAL)  XMEMORYORG   XMEMORYSIZE       apply
#endif

#wcodorg	watcode  (DATASEGVAL)  WATCHCODEORG WATCHCODESIZE     apply

/*--------------------------------------------------------------------
**  DATA ORG statements to determine data locations in physical and
**  logical memory space.
**
**  Type Name     Segment        Top          Size			  	 Use
-------------------------------------------------------------------*/
#rvarorg rootdata	(DATASEGVAL) 	ROOTDATAORG  ROOTDATASIZE 	 apply


//**** internal and external vector table locations *****************
#define XINTVEC_BASE  STACKORG-0x100
#define INTVEC_BASE STACKORG-0x200


/************************** LOGICAL MEMORY MAP **********************

  FFFF                          ---------------			
                                |             |
                                |             |
                                ~             ~
                                     Xmem
                                ~             ~
                                |             |
                                |             |
  E000                          ---------------
                                | Stack Top   |
                                |             |
                                ~             ~
                                     Stack
                                ~             ~
                                |             |
                                |             |
  STACKORG                      ---------------	
                                | external    |
                                | vector tabl.|
  STACKORG-100h                 ---------------				
                                | internal    |
                                | vector tabl.|
  STACKORG-200h                 ---------------
                                |     |       |
                                |    /|\      |
                                |     |       |
                                ~             ~
                                  Watch Code
                                ~             ~
                                |     |       |
                                |    \|/      |
   WATCHCODEORG                 |     |       |
                                ---------------
   ROOTDATAORG                  |     |       |
                                |    /|\      |
                                |     |       |
                                ~             ~
                                   Root Data
                                ~             ~
                                |     |       |
                                |    \|/      |
                                |     |       |
                                ---------------
                                |     |       |
                                |    /|\      |
                                |     |       |
                                ~             ~
                                   Root Code
                                ~             ~
                                |     |       |
                                |    \|/      |
                                |     |       |
  ROOTCODEORG (0000)            ---------------
    
*******************************************************************/


//***** Libraries needed by the BIOS *********************************
#use BIOSFSM.LIB 						// The communication Finite State Machine
#use SYSIO.LIB 						// IO register assignemnts and functions
#use DBUGKERN.LIB						// The debug kernel
#use CSUPPORT.lib						// Some C support functions
#use FLASHWR.lib						// The flash writing functions
#use STACK.lib							// The stack initialization functions
#use IDBLOCK.LIB						// Flash ID block access fcns (and CRC).
#use ERRORS.LIB						// Runtime error handling
#use TC.LIB                      // New-style target communications
#use TC_SYSTEMAPP.LIB				// The System-type handler
#use DKCORE.LIB						// Debug kernel
#use DKAPP.LIB							// Debug kernel - target communications interface
#use cpuparam.lib					// CPU-specific settings


#if (ENABLE_CLONING == 1)
#use CLONE.LIB							// Contains cloning support functions
#endif

/********************************************************************
*********************************************************************
*
*	BIOS internals follow
*
*********************************************************************
*********************************************************************/
#if (NUM_FLASH_WAITST==0)
#define FLASH_WSTATES 0xc0
#else
#if (NUM_FLASH_WAITST==1)
#define FLASH_WSTATES 0x80
#else
#if (NUM_FLASH_WAITST==2)
#define FLASH_WSTATES 0x40
#else
#if (NUM_FLASH_WAITST==4)
#define FLASH_WSTATES 0x00
#endif
#endif
#endif
#endif

#if (NUM_RAM_WAITST==0)
#define RAM_WSTATES 0xc0
#else
#if (NUM_RAM_WAITST==1)
#define RAM_WSTATES 0x80
#else
#if (NUM_RAM_WAITST==2)
#define RAM_WSTATES 0x40
#else
#if (NUM_RAM_WAITST==4)
#define RAM_WSTATES 0x00
#endif
#endif
#endif
#endif

#if (NUM_CS2_WAITST==0)
#define CS2_WSTATES 0xc0
#else
#if (NUM_CS2_WAITST==1)
#define CS2_WSTATES 0x80
#else
#if (NUM_CS2_WAITST==2)
#define CS2_WSTATES 0x40
#else
#if (NUM_CS2_WAITST==4)
#define CS2_WSTATES 0x00
#endif
#endif
#endif
#endif

#define SIZESTDIOBUFF 130

#define HW_MEMBREAK 0xe2

// disable clock spreader if not Rabbit 3000 CPU
#if (_CPU_ID_ != R3000)
	#undef ENABLE_SPREADER
	#define ENABLE_SPREADER	0
#endif

/*** end of macro definitions */

/*** variable definitions */
#define BIOSSTACKSIZE 40
char dbXPC;

void *dkcState;			//	the address (state) of  debugger kernel comm machine
char BiosStack[BIOSSTACKSIZE]; // initial stack for bios in data the segment
char commBuffer[256];	//	communication buffer
char stdioCommBuff[SIZESTDIOBUFF];
char watchBuffer[8];		//	buffer for watch expression results

struct _fcTable fcTable;			//	RAM location to store the fctable
char stepRelay[3];		//	ram location for rst28 relay

struct _dcParam DCParam;

struct _DCSrcDebug DCSrcDebug;
char  OPMODE, _dkfirst, cloningNow;

/*** do not change the order of definition */
struct _dkControl dkControlFlags;
struct _regBuffer registers;			//	RAM location to store the registers
char _dkenable28,_dkdisable28; 		// byte to store at RST28 enable, disable
int _SectorSize;
char	freq_divider;						// time constant for 19200 baud

// store value of GCSR register to determine reset reason
char	reset_status;					

// the internal I/O shadow registers
char GCSRShadow, GOCRShadow, GCDRShadow;
char PADRShadow;
char PBDRShadow;
char PCDRShadow, PCFRShadow;
char PDDRShadow, PDCRShadow, PDFRShadow, PDDCRShadow, PDDDRShadow;
char PEDRShadow, PECRShadow, PEFRShadow, PEDDRShadow;

char MMIDRShadow, MECRShadow;
char MB3CRShadow, MB2CRShadow, MB1CRShadow, MB0CRShadow;
char IB0CRShadow, IB1CRShadow, IB2CRShadow, IB3CRShadow, IB4CRShadow, 
     IB5CRShadow, IB6CRShadow, IB7CRShadow;
char I0CRShadow, I1CRShadow;
char TACSRShadow, TACRShadow, TAT1RShadow, TAT2RShadow, TAT3RShadow,
	  TAT4RShadow, TAT5RShadow, TAT6RShadow, TAT7RShadow;
char TBCSRShadow, TBCRShadow;
char SPCRShadow, SACRShadow, SBCRShadow, SCCRShadow, SDCRShadow,
	  SECRShadow, SFCRShadow;
char SAERShadow, SBERShadow, SCERShadow, SDERShadow;

#if (_CPU_ID_ == R3000)
// Rabbit 3000-specific registers
char GPSCRShadow;
char MTCRShadow;
char PBDDRShadow;
char PFDRShadow, PFCRShadow, PFFRShadow, PFDDRShadow, PFDCRShadow;
char PGDRShadow, PGCRShadow, PGFRShadow, PGDDRShadow, PGDCRShadow;
char GCM0RShadow, GCM1RShadow;
char BDCRShadow;
char ICCSRShadow, ICCRShadow;
char ICT1RShadow, ICS1RShadow, ICT2RShadow, ICS2RShadow;
char PWL0RShadow, PWM0RShadow, PWL1RShadow, PWM1RShadow,
	  PWL2RShadow, PWM2RShadow, PWL3RShadow, PWM3RShadow;
char QDCSRShadow, QDCRShadow;
char SEERShadow, SFERShadow;
char TAPRShadow;
char TAT8RShadow, TAT9RShadow, TAT10RShadow;
#endif

char NewPrintConFlag;

struct progStruct {
	ADDR24      RCB,RCE,    // root code (Begin and End)
					XCB,XCE,    // extended code (Begin and End)
					RDB,RDE,    // root data (Begin and End)
					XDB,XDE;		// extended data (RAM) (Begin and End)
	unsigned short  auxStkB,// aux stack Begin
					auxStkE,    // end
					stkB,       // stack begin
					stkE,       // end
					freeB,      // free begin
					freeE,      // end
					heapB,      // heap begin
					heapE;      // end
	}; 

// dc_timestamp and prog_param are defined by the compiler.	
extern struct progStruct prog_param;
// date/time stamp at the end of the compile (seconds since Jan. 1 1980)
extern long dc_timestamp;


#if (ERRLOG_USE_MESSAGE==1)
	char   errlogMessage[8];
#endif
#if (ENABLE_ERROR_LOGGING==1)

struct _errLogInfo  errLogInfo;
struct _errLogEntry  errLogEntry;

#endif  // end if error logging enabled

/*** end of contiguous definition */

/*** end of variable definitions */
/*Begin Header prototypes**************/
 root void biosmain();
 root void dkInit();
 xmem void WaitSettle();
 xmem void dkInitTC();
 root void dkcDoSerial();
 root void DevMateSerialISR();
 root void DevMateReadPort();
 root void DevMateWritePort();
 root void divider19200();
 xmem void dkInitFCTable();
 root void dkDoMsg();
 root void __bp_init();
 xmem void dkBLDebugInit();
 root void _xexit();
 xmem void dkSetIntVecTabP();
 xmem void dkSetIntVecTabR();
 root void dkStartup();
 root void dkEnd();
 root void symTab();
 root void AUX_STACK_LIMIT();
 root void AUX_STACK_PTR();
 root void STACK_LIMIT();
 root void symTabEnd();
/*End Header***************************/
#ifndef _TARGETLESS_COMPILE_
#define _TARGETLESS_COMPILE_ 0
#endif
#if (NUM_RAM_WAITST!=0)
#pragma DATAWAITSUSED on
#endif
#asm nodebug
biosmain::
// don't insert any code inbetween this label and the jp
// or the jp and the dw!!!
#ifdef _FLASH_
	jp		InFlashNow
#else
	jp		InRAMNow
#endif
	dw		fcTable		;	pointer to the RAM-based fcTable	
divider19200::
	db 	_FREQ_DIV_19200_    ;  frequency divider for 19200 baud (value from coldloader)
loaderParameters:
	dw		BIOSCodeEnd	;	store BIOS size, RAM start location, and
#ifdef _FLASH_
	dw 0
#else	
	dw		InRAMNow
#endif

//*** These 4 labels and their data must be kept below address 0x80 !
ErrLogConfiguration::
	dw 	0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff
ErrLogLastHeader::
	dw 	0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff
I_am_a_clone::
	dw    0
I_am_a_sterile_clone::
	db    0

InFlashNow::
#ifdef _FLASH_

dkInit::
ljp __dkinit__

#endasm

#asm xmem
__dkinit__::
	; set STATUS pin low and CLK pin off
	ld		a,0xA0
	ioi 	ld		(GOCR),a
	ld		a,00001000b	;	normal oscilator, processor and peri.
								;	from main clock, no periodic interrupt
	ioi   ld	(GCSR),a
#endif

#ifdef _RAM_
InRAMNow::
	xor   a
	ld    (I_am_a_clone),a

	ipset 3

//****** a slight delay for things to settle
	ld    b,50
	ld    de,0e8h        ; the upper 3 bits turn over every 1/1024 s
	ld    h,0
oloop:
	ld    a, 0x5a
	ioi 	ld (WDTCR),a	
	ld		a,0ffh			;write any value to 0r to capture count
	ioi	ld (RTC0R),a
	ld		iy,RTC0R
	ioi	ld L,(iy)
	and   hl,de
loop:	
	ld		a,0ffh			;capture and compare
	ioi	ld (RTC0R),a
	ld		iy,RTC0R
	ioi	ld a,(iy)
	and   e
	cp    L
	jr    z,loop
	djnz  oloop         ; loop until the first value reached  


	; set STATUS pin low and CLK pin off
	ld		a,0xA0
	ioi 	ld		(GOCR),a
	ld		a,00001000b		;	normal oscilator, processor and peri.
								;	from main clock, no periodic interrupt
	ioi   ld	(GCSR),a
#endif

dkSetMMU:
	ld 	a,MEMBREAK
	ioi 	ld (SEGSIZE), a
	ld 	a, DATASEGVAL
	ioi 	ld (DATASEG), a	

#if (CS1_ALWAYS_ON==0)
	xor 	a
#else	
	ld 	a, 0x10
#endif
	ioi 	ld (MMIDR),a

	;; set up temporary stack in RAM
	ld		hl, BiosStack
	ld		de, BIOSSTACKSIZE-1
	add	hl, de
	ld		sp, hl

#ifdef _FLASH_
	ld 	a, MB0CR_SETTING
	ioi 	ld (MB0CR),a
	ld 	a, MB1CR_SETTING
	ioi 	ld (MB1CR),a
	ld 	a, MB2CR_SETTING
	ioi 	ld (MB2CR),a
	ld 	a, MB3CR_SETTING
	ioi 	ld (MB3CR),a

#if (CS1_ALWAYS_ON==0)
	xor 	a
#else	
	ld 	a, 0x10
#endif
	ld 	hl,MMIDRShadow
	ld    (hl),a
	ld 	a, MB0CR_SETTING
	ld 	hl,MB0CRShadow
	ld    (hl),a
	ld 	a, MB1CR_SETTING
	ld 	hl,MB1CRShadow
	ld    (hl),a
	ld 	a, MB2CR_SETTING
	ld 	hl,MB2CRShadow
	ld    (hl),a
	ld 	a, MB3CR_SETTING
	ld 	hl,MB3CRShadow
	ld    (hl),a
	ioi	ld a, (GCSR)
	ld		(reset_status), a		; save bits in GCSR to determine reason for reset

   lcall _more_inits0
#endif // end of FLASH section


#ifdef _RAM_
	ld 	a, MB0CR_SETTING
	ioi 	ld (MB0CR),a
	ld 	a, MB1CR_SETTING
	ioi 	ld (MB1CR),a
	ld 	a, FLASH_WSTATES | CS_FLASH
	ioi 	ld (MB2CR),a
	ld 	a, FLASH_WSTATES | CS_FLASH
	ioi 	ld (MB3CR),a

	ld 	a, MB0CR_SETTING
	ld 	hl,MB0CRShadow
	ld    (hl),a
	ld 	a, MB1CR_SETTING
	ld 	hl,MB1CRShadow
	ld    (hl),a
	ld 	a, FLASH_WSTATES | CS_FLASH
	ld 	hl,MB2CRShadow
	ld    (hl),a
	ld 	a, FLASH_WSTATES | CS_FLASH
	ld 	hl,MB3CRShadow
	ld    (hl),a

//  Before we disable the flash, disable any existing
//  flash BIOS by writing a tight loop to the start 
//  of flash. This ensures that runmode will not work
//  until the BIOS and user program have been recompiled
//  to flash. This prevents the user from deploying a board
//  when he just compiled and debugged to RAM, because when
//  power cycles and the programming cable is not connected,
//  the previously loaded flash BIOS, if it exists, will run
//  the previously loaded user program, if it exists.

	ld		hl, 0x04 | 0x08
	call	_readIDBlock
	bool	hl
	jr		z, idBlockOk
	;; erase SysIDBlock if error retured
	ld		hl, SysIDBlock
	ld		b, SysIDBlock+marker+6-SysIDBlock
	xor	a
blockEraseLoop:
	ld		(hl), a
	inc	hl
	djnz	blockEraseLoop
idBlockOk:

	// this will disable the flash,
	// everything mapped to RAM now.
	ld 	a, MB2CR_SETTING
	ioi 	ld (MB2CR),a
	ld 	a, MB3CR_SETTING
	ioi 	ld (MB3CR),a

#if (CS1_ALWAYS_ON==0)
	xor 	a
#else	
	ld 	a, 0x10
#endif
	ld 	hl,MMIDRShadow
	ld    (hl),a
	ld 	a, RAM_WSTATES   | 0x05 | (MB2CR_INVRT_A18<<4) | (MB2CR_INVRT_A19<<5)   
	ld 	hl,MB2CRShadow
	ld    (hl),a
	ld 	a, RAM_WSTATES   | 0x05 | (MB3CR_INVRT_A18<<4) | (MB3CR_INVRT_A19<<5)   
	ld 	hl,MB3CRShadow
	ld    (hl),a

#endif // end of RAM section

	lcall _more_inits02

#ifdef _RAM_ 
;******************************************************************************
; Enter here for sofware reset requested by Dynamic C
; to turn off periodic interrupt
dkInit::
	ipset 3	
	ld		a,00001000b		;	normal oscilator, processor and peri.
								;	from main clock, no periodic interrupt
	ioi   ld	(GCSR),a

;*******************************************************************************
#endif

	;	initialize comm ports now
	;	at port a, async, 8-bit, interrupt priority 1
	; make sure other serial ports are disabled
	ld		a, 0x00
	ioi	ld (SBCR), a
	ioi	ld (SCCR), a
	ioi	ld (SDCR), a
	ld		a, 0x01
	ioi 	ld (SACR),a
	ld 	hl,SACRShadow
	ld    (hl),a

dkSetSP:
	ld		hl,BiosStack			; Set up a temporary stack to perform call.
	ld    de,BIOSSTACKSIZE-1   ; Note that stack segment register is not setup here,
	add    hl,de					; but in _ProgStkSwitch.  _ProgStkSwitch is normally
	ld		sp,hl						; called in premain after stack alloc init.

dkSetComm:
	lcall	dkInitTC
	lcall	dkSetIntVecTabP

dkSetProgPort::
	;	parallel port D, bit 6,0 as output lines
	ld		a,0xc3		;	jump instruction
	ld		(INTVEC_BASE+SERA_OFS),a
	ld		hl,DevMateSerialISR
	ld		(INTVEC_BASE+SERA_OFS+1),hl

#if (ENABLE_CLONING == 1)
	ld    a,(I_am_a_sterile_clone)
	or    a
	jr    nz,_skip_clone_check

	;; see if cloning cable is attached (was PB1 low?)
	ld		a, (cloningNow)
	or		a
	jr		z, NotCloning
	ljp		CloneMode
NotCloning:
#endif

_skip_clone_check:

	lcall _init_IO_regs
			
	// Ignore SMODE pins
	//  Dynamic C does this, but need to do it running stand alone too.
	ld    a,0x80
	ioi	ld (SPCR), a
	ld		(SPCRShadow), a

#ifndef COMPILE_SECONDARY_PROG
	// check for run mode		
	ioi ld a,(SPCR)
	and 60h
	cp  60h
	jp  nz,RunMode 
	; Reset 
#else
	// can't debug secondary program, so run it
	jp  RunMode 
#endif

#if (ENABLE_CLONING==1)
	ld a,(I_am_a_clone)
	or a
	jp nz,RunMode
#endif

 	jp __dktrap   // switch back to root

#endasm

#asm 
__dktrap::
	lcall _init_dkLoop

	call	dkSaveContext
	call	dkCore
	jp 	__dktrap			
	
RunMode:
	ipset 3
	lcall dkSetIntVecTabR       ;  disable debug RSTs
	ipset 0

#ifdef _RAM_ 
	ld hl,OPMODE
	ld (hl),0x80
	jp StartUserCode	
#endif

#ifdef _FLASH_
	ld 	a,80h
	ld   	(OPMODE),a

	lcall	WaitSettle

	jp StartUserCode	

#endif


#endasm

#asm xmem
;; This code repeatedly measures the timing on the 32kHz oscillator until
;; it matches twice in a row.  The 32kHz oscillator circuit could take as
;; long as 1.5 seconds to rise to a full voltage and we want to wait until
;; that is true...

WaitSettle::
	ld		de, 0000h				// first measurement value
	push	de							// save it for later
startmeas:
	ld		bc, 0000h				// our counter
	ld		de, 07FFh				// mask for RTC bits
wait_for_zero:
	ioi	ld (RTC0R), a			// load RTC registers
	ioi	ld hl, (RTC0R)			// read 1st two RTC registers
	and	hl, de					// mask off bits
	jr		nz, wait_for_zero		// repeat until all zero
timing_loop:
	inc	bc							// increment counter
	push	bc							// save counter
	ld		b, 057h					// empirically-derived loop counter
	ld		hl, WDTCR
delay_loop:
	ioi	ld	(hl), 05Ah			// hit watchdog
	djnz	delay_loop
	pop	bc							// restore counter
	ioi	ld (RTC0R), a			// load RTC registers
	ioi	ld hl, (RTC0R)			// read 1st two RTC registers
	bit	2, h						// test bit for 0800h
	jr		z, timing_loop			// if nonzero, keep looping
	
	ld		h, b						// h = upper nibble of counter
	ld		a, c						
	add	a, 08h					// (effectively rounding up)
	ld		l, a						// l = lower nibble of counter + 8
	rr		hl
	rr		hl
	rr		hl							// divide by 16
	rr		hl
	ld		a, l						// lower nibble is divisor!
	dec	a
	pop	de							// get last count
	cp		a, e						// compare last and current counts
	jr		z, donemeas				// if alike, done	
	ld		e, a
	push	de							// save this count
	jr		startmeas
donemeas:
	lret
	
dkInitTC::
	ld		hl,DevMateReadPort
	ld		(TCState+[TCState]+ReadPort),hl		; the low-level read driver
	ld		hl,DevMateWritePort
	ld		(TCState+[TCState]+WritePort),hl		; the low-level write driver
	ld		hl,DevMateClearReadInt
	ld		(TCState+[TCState]+ClearReadInt),hl	; low-level driver to clear spurious ints
	ld		hl,dkcRXBufferListStore
	ld		(TCState+[TCState]+RXBufferList),hl	; the list of receive buffers, sorted by 'type'
	ld		hl,dkcCallbackListStore
	ld		(TCState+[TCState]+CallbackList),hl	; the list of callbacks, sorted by 'type'
	ld		hl,dkcSystemWriteHeader
	ld		(TCState+[TCState]+SysWriteHandler),hl	; special-case hander for sys-writes
	xor	a
	inc	a
	ld		(TCState+[TCState]+TrapSysWrites),a		; flag that sys-writes should be handled as a special case

	ld		iy,TCState
	lcall	dkcSystemBufINIT		;  initialize the system buffers
	lcall	dkcInit					;	initialize comm module
	call	dkcSystemINIT			;  initialize the system-type handler
	lcall	dkInitFcTable			;	initialize the 3-table
	lcall	dkBLDebugInit
	call	dkInitDebugKernelComs ; initial debug kernel - target communication interface
	lret		
#endasm

#asm
dkcDoSerial::
	ld		iy,TCState			; iy == pointer to our state structure	
	ioi 	ld a,(SASR)			;	check the status
	bit	SS_RRDY_BIT,a			;  was a character received?
	jr		z,_DevMatenoRxIntReq

	call	dkcEntryRX			;  handle the RX interrupt
	jr		_DevMatereadyToExit		;  all done for now

_DevMatenoRxIntReq:
	bit	2,a
	jr		z,_DevMateSecondTXInt
	call	dkcEntryTX			;	handle the TX interrupt
	jr		_DevMatereadyToExit

_DevMateSecondTXInt:
	ld		a,(TCState+[TCState]+TXBusy)
	or		a
	jr		z,_DevMateSkipInt

	; this really is a good int
	call	dkcEntryTX
	jr		_DevMatereadyToExit

_DevMateSkipInt:
	; just clear the int
	ioi 	ld (SASR), a

_DevMatereadyToExit:
	ret

DevMateSerialISR::
	;	serial interrupt handler
	push	ip
	push	af
	ex    af,af'
	push	af
	ld    a,xpc
	push	af
	push	bc
	push	de
	push	hl
	push  ix
	push	iy

	exx
	push	bc
	push	de
	push	hl

	call	dkcDoSerial
	
	pop	hl
	pop	de
	pop	bc
	exx

	pop	iy
	pop   ix		
	pop	hl
	pop	de
	pop	bc
	pop	af
	ld    xpc,a
	pop	af
	ex    af,af'
	pop	af
	pop	ip
	ipres
	ret

DevMateReadPort::
	;	destroys A
	;	returns byte read (if any) in A
	;	returns with Z set if nothing is read
		
	;	check if there is anything available
	ioi 	ld a, (SASR)
	bit	SS_RRDY_BIT,a		;	if a received byte ready?
	ret	z						;	nope, return with z set
	;	otherwise, a byte *is* ready, read from data port
	ioi 	ld a, (SADR)
	ret							;	return with z *not* set

DevMateClearReadInt::
	ld		a,SS_RRDY_BIT
	ioi	ld (SASR),a
	ret
	
DevMateWritePort::	;	assumes byte to transmit is in C
	;	destroys A
	;	returns with Z reset if not transmitted
		
	;	check if the port is ready
	ioi 	ld a, (SASR)
	bit	SS_TFULL_BIT,a		;	can I transmit now?
	ret	nz						;	nope, return with nz set
	;	otherwise, the transmit buffer is ready, write to it!
	ld		a,c					;	move byte to transmit to a
	ioi 	ld (SADR), a
	ret							;	return with z *not* set

	nop
dkDCID::
	db "DynamiC"
dkProdName::
	db PRODUCT_NAME
#endasm

#asm xmem
dkInitFcTable::
	;	initialize the fctable here

;	zero out everything first
	ld		hl,fcTable
	ld		b,_fcTable+@LENGTH
	xor	a
dkInitFCClrByte:
	ld		(hl),a
	inc	hl
	djnz	dkInitFCClrByte
	
;struct _fcTable {
;	char DCID[7];			//	this field should contain "DynamiC"
	ld		hl,dkDCID				;	note that this DCID is name of the string
	ld		de,fcTable+DCID	;	note that this DCID is a field ID
	ld		bc,7
	ldir  
;	char majorRev;			//	major revision
	ld		a,0x02
	ld		(fcTable+majorRev),a
;	char minorRev;			//	minor revision
	ld		a,0x00
	ld		(fcTable+minorRev),a
;	char targetName[8];	//	name of target
	ld		hl,dkProdName			;	name of string
	ld		de,fcTable+targetName
	ld		bc,8
	ldir
;	void *symTable;		//	pointer to symbol table
	ld		hl,symTab			;	symbol table address
	ld		(fcTable+symTable),hl
;	unsigned checksum;	//	checksum for library
;	void *codeBase;		//	base of code area
	ld		hl,0x2000
	ld		(fcTable+codeBase),hl
;	void *dataTop;			//	top of code
	ld		hl,0xda00
	ld		(fcTable+dataTop),hl
;	void *dataBase;		//	base (bottom) of data
	ld		hl,0x2000
	ld		(fcTable+dataBase),hl
;	void *codeTop;			//	top of data
	ld		hl,0xd900
	ld		(fcTable+codeTop),hl
;### needs to be filed
;	void *dbgStack;		//	pointer to debug stack
	bool	hl					// set the stack from the current stack pointer
	ld		l,a
	add	hl,sp
	ld		(fcTable+dbgStack),hl	;	note that this is the field dkDbgStack
;	void *stepVector;		//	stepping breakpoint vector
	ld		hl,stepRelay ;INTVEC_BASE+RST28_OFS			;	stepRelay
	ld		(fcTable+stepVector),hl
;	char chDisStep;		//	character to stop stepping breakpoint
	ld		a,0xc9			;	code for return
	ld		(fcTable+chDisStep),a
;	char chEnbStep;		//	character to enable stepping breakpoint
	ld		a,0xc3			;	code for jp
	ld		(fcTable+chEnbStep),a
;	void *trapVector;		//	pointer to TRAP development vector
;	void *rst38Vector;	//	pointer to RST 38 development vector
;	void *PFVector;		//	pointer to powerfail vector
;	### requires changes, hard coded for now
	ld		hl,0x22f3
	ld		(fcTable+PFVector),hl
;	void *commTable;		//	pointer to communication table
	ld		hl,dkControlFlags+commPtr
	ld		(fcTable+commTable),hl
;	char commAttn;			//	communication attention flag
	ld		hl,dkControlFlags+commAttn
	ld		(hl),0
;	char ramSize;			//	size of ram in 4kbyte pages
;### requires changes, hard coded for now
//	call	CheckRamSize
	ld		a,RAM_SIZE ;			;	128kbyte RAM

	ld		(fcTable+ramSize),a
;	char memBreak;			//	CBAR value
;### requires changes, hard coded for now
	ld		a,HW_MEMBREAK			;	typical EPROM/RAM break
	ld		(fcTable+memBreak),a
;	void *nextBankV;		//	next bank vector
;	void *biosEnd;			//	end of BIOS
	ld		hl,dkEnd
	ld		(fcTable+biosEnd),a
;	char xcodeTop;			//	top of xmem code
;this field doesn't seem to be used?
;	char ramStart;			//	start address of RAM in 4kbyte pages
;### requires changes, hard coded for now
	ld		a,RAM_START			;	typical RAM mapping
	ld		(fcTable+ramStart),a
   ld 	hl, _xexit
   ld    (DCParam+errorExit), hl  ; initialize error exit
	lret
#endasm

#asm

#define ERROR_EXIT DCParam+errorExit
bioshitwd::
	push  af
	ld    a, 0x5a
	ioi 	ld (WDTCR),a	
	pop  af
	ret
#endasm

#asm
dkDoMsg::
	call	dkSendStdio
	ret
#endasm

#asm xmem
; initialize portions of debug kernel that need to be done at
; the bios level
dkBLDebugInit::
	bool	hl
	ld		l,h
	ld		(dkLastAsmStart),hl
	ld		(dkLastAsmEnd),hl
	ld		(dkExitHook),hl
	ld		(dkSingleStepHook),hl
	ld		(dkPrologHook),hl
	ld		(dkEpilogHook),hl
	ld		(dkSetStdioTimerHook),hl
	ld		(dkCheckStdioTimeOutHook),hl
	xor	a
	ld		(dkAckToSend),a
	ld		(dkLocks),a
	ld		(dkStatusFlags),a
	ld		(dkPrologCount),a
	ld		(dkCharData),a
	ld		(dkCharReady),a
	lret
#endasm

#asm
_xexit::
	push	af
	ld		a,(dkSendFlags)
	set	DKF_SEND_STATUS,a
	set	DKF_SEND_ACK,a
	ld		(dkSendFlags),a
	ld		a,(dkStatusFlags)
	res	DKF_STAT_RUNMODE,a
	set	DKF_STAT_ATEXIT,a
	set	DKF_STAT_AT_BP,a
	ld		(dkStatusFlags),a
	ld		a,TC_DEBUG_ATBREAKPOINT
	ld		(dkAckToSend),a
	ld		a,(OPMODE)							;if board is in runmode, don't reenable rst 20
	and	8
	jr		z, _xexit_skiprst20enable
	ld		a,0xc3
	ld		(INTVEC_BASE+RST20_OFS),a
_xexit_skiprst20enable:
	pop	af
	rst	0x20
__xexit__::
	ipset 3
	ld    a,0x53
	ioi   ld (WDTCR),a
_xexitLoop:
	jr		_xexitLoop
#endasm



#asm xmem
	
dkSetIntVecTabP::	 ; Program mode
	;	set up interrupt vector table
	ld		a,0xff & (INTVEC_BASE >> 8)	;
	ld		iir,a
	ld		a,0xff & (XINTVEC_BASE >> 8)	;
	ld		eir,a
	lret

dkSetIntVecTabR::   ; Runmode
	;	set up interrupt vector table
	ld		a,0xff & (INTVEC_BASE >> 8)	;
	ld		iir,a
	ld		a,0xff & (XINTVEC_BASE >> 8)	;
	ld		eir,a
	ld		a,0xc9		;	this is the ret instruction
	ld		(INTVEC_BASE+RST18_OFS),a		;	all are relays
	ld		(INTVEC_BASE+RST20_OFS),a
	ld		(INTVEC_BASE+RST28_OFS),a
	lret

_more_inits0::

#if (ENABLE_ERROR_LOGGING==1)
	lcall  errlogRecordStartStatus
#endif

#if (_FLASH_SIZE_ == 0x80)
	ld		hl, 0x01 | 0x02
#else
	ld		hl, 0x01
#endif

#ifdef COMPILE_SECONDARY_PROG
	// we are running the second flash
   ld    a,FLASH_WSTATES
	and   0xfc          // set control bits to 1rst flash
	ioi   ld (MB1CR),a
	ld		hl, 0x03
#endif

	call	_readIDBlock

#ifdef COMPILE_SECONDARY_PROG
   ld    a,MB1CR_SETTING
	ioi   ld (MB1CR),a
#endif

	bool	hl
	jr		z, idBlockOk
	;; erase SysIDBlock if error retured
	ld		hl, SysIDBlock
	ld		b, SysIDBlock+marker+6-SysIDBlock
	xor	a
blockEraseLoop:
	ld		(hl), a
	inc	hl
	djnz	blockEraseLoop
idBlockOk:

#if (_FLASH_SIZE_ == 0x80)
	ld		hl, 0x01 | 0x02
#else
	ld		hl, 0x01
#endif
	call	_InitFlashDriver

#if (ENABLE_ERROR_LOGGING==1)
	call  InitializeErrorLog
#endif
	lret
	
//**************************************************************
_init_IO_regs::
	// The following registers have specific values already
	// set by the BIOS and loaded into their shadow registers:
	//		GCSR, WDTCR, GCMxR, GOCR, GCDR, MBxCR, MTCR,
	//		 SPCR, PCDR, PCFR, TACSR, TACR, SACR
	//
	// This next set of registers will be reset to these values
	// upon reset, startup, and when debugging is ended (i.e.
	// pressing F4).

	xor	a							// a = 0x00
	ioi	ld (PADR), a
	ld		(PADRShadow), a
	ioi	ld (PBDR), a
	ld		(PBDRShadow), a
	ioi	ld (PCDR), a
	ld		(PCDRShadow), a

	ioi	ld	(PDDDR),a
	ld		(PDDDRShadow),a
	ioi	ld (PDDR), a
	ld		(PDDRShadow), a
	ioi	ld (PDCR), a
	ld		(PDCRShadow), a
	ioi	ld (PDFR), a
	ld		(PDFRShadow), a
	ioi	ld (PDDCR), a
	ld		(PDDCRShadow), a
	ioi	ld	(PEDDR),a
	ld		(PEDDRShadow),a
	ioi	ld (PEDR), a
	ld		(PEDRShadow), a
	ioi	ld (PECR), a
	ld		(PECRShadow), a
	ioi	ld (PEFR), a
	ld		(PEFRShadow), a
	
	ioi	ld (TBCSR), a
	ld		(TBCSRShadow), a
	ioi	ld (TBCR), a
	ld		(TBCRShadow), a

	ioi	ld (IB0CR), a
	ld		(IB0CRShadow), a
	ioi	ld (IB1CR), a
	ld		(IB1CRShadow), a
	ioi	ld (IB2CR), a
	ld		(IB2CRShadow), a
	ioi	ld (IB3CR), a
	ld		(IB3CRShadow), a
	ioi	ld (IB4CR), a
	ld		(IB4CRShadow), a
	ioi	ld (IB5CR), a
	ld		(IB5CRShadow), a
	ioi	ld (IB6CR), a
	ld		(IB6CRShadow), a
	ioi	ld (IB7CR), a
	ld		(IB7CRShadow), a

	ioi	ld (I0CR), a
	ld		(I0CRShadow), a
	ioi	ld (I1CR), a
	ld		(I1CRShadow), a

	ioi	ld (TAT1R), a
	ld		(TAT1RShadow), a

	ioi	ld (SBCR), a
	ld		(SBCRShadow), a
	ioi	ld (SCCR), a
	ld		(SCCRShadow), a
	ioi	ld (SDCR), a
	ld		(SDCRShadow), a
		
	ld    a,0x80					// ingore SMODE pins --  Dynamic C does this,
	ioi	ld (SPCR), a			// but need to do it running stand alone too.
	ld		(SPCRShadow), a

#if (_CPU_ID_ == R3000)
	xor	a							// a = 0x00
	ioi	ld (GPSCR), a
	ld		(GPSCRShadow), a
	ioi	ld (BDCR), a
	ld		(BDCRShadow), a
	ioi	ld (MECR), a
	ld		(MECRShadow), a

	ioi	ld (PFDR), a
	ld		(PFDRShadow), a
	ioi	ld (PFCR), a
	ld		(PFCRShadow), a
	ioi	ld (PFFR), a
	ld		(PFFRShadow), a
	ioi	ld (PFDCR), a
	ld		(PFDCRShadow), a
	ioi	ld (PFDDR), a
	ld		(PFDDRShadow), a

	ioi	ld (PGDR), a
	ld		(PGDRShadow), a
	ioi	ld (PGCR), a
	ld		(PGCRShadow), a
	ioi	ld (PGFR), a
	ld		(PGFRShadow), a
	ioi	ld (PGDCR), a
	ld		(PGDCRShadow), a	
	ioi	ld (PGDDR), a
	ld		(PGDDRShadow), a

	ioi	ld (PWL0R), a
	ld		(PWL0RShadow), a
	ioi	ld (PWM0R), a
	ld		(PWM0RShadow), a
	ioi	ld (PWL1R), a
	ld		(PWL1RShadow), a
	ioi	ld (PWM1R), a
	ld		(PWM1RShadow), a
	ioi	ld (PWL2R), a
	ld		(PWL2RShadow), a
	ioi	ld (PWM2R), a
	ld		(PWM2RShadow), a
	ioi	ld (PWL3R), a
	ld		(PWL3RShadow), a
	ioi	ld (PWM3R), a
	ld		(PWM3RShadow), a
	
	ioi	ld (ICCSR), a
	ld		(ICCSRShadow), a
	ioi	ld (ICCR), a
	ld		(ICCRShadow), a
	ioi	ld (ICT1R), a
	ld		(ICT1RShadow), a
	ioi	ld (ICT2R), a
	ld		(ICT2RShadow), a
	ioi	ld (ICS1R), a
	ld		(ICS1RShadow), a
	ioi	ld (ICS2R), a
	ld		(ICS2RShadow), a


	ioi	ld	(PWL0R), a
	ld		(PWL0RShadow), a
	ioi	ld	(PWM0R), a
	ld		(PWM0RShadow), a
	ioi	ld	(PWL1R), a
	ld		(PWL1RShadow), a
	ioi	ld	(PWM1R), a
	ld		(PWM1RShadow), a
	ioi	ld	(PWL2R), a
	ld		(PWL2RShadow), a
	ioi	ld	(PWM2R), a
	ld		(PWM2RShadow), a
	ioi	ld	(PWL3R), a
	ld		(PWL3RShadow), a
	ioi	ld	(PWM3R), a
	ld		(PWM3RShadow), a

	ioi	ld (QDCSR), a
	ld		(QDCSRShadow), a	
	ioi	ld (QDCR), a
	ld		(QDCRShadow), a

	ld		a, 0xC0
	ld		(PBDDRShadow), a

	ld		a, 0x01
	ld		(TAPRShadow), a
#endif
   lret

//**************************************************************
// Init. the status pin, clocks, clock doubler, programming baud
// rate, stdio comm buffer

_more_inits02::
	; set STATUS pin low and CLK pin off
	ld		a, 0xA0
	ld		hl, GOCRShadow
	ld		(hl), a

	ld		a,00001000b			;	normal oscilator, processor and peri.
	ld 	hl, GCSRShadow
	ld    (hl), a

	lcall	_getDoublerSetting
	ld		a, l
	ld		(GCDRShadow), a
	ioi	ld (GCDR), a		; set clock doubler now

#if (ENABLE_SPREADER > 0)
	lcall	_enableClockModulation
#endif

	ld		a, 0c0h
	ioi	ld (PCFR), a	; as initialized in pilot
	ld 	hl, PCFRShadow	
	ld    (hl), a			

	ld    a,0xA0h
	ld		(statusPinState),a
	
	ld 	a,88h
	ld   	(OPMODE),a

	ld 	a,0
	ld   	(_dkfirst),a

#if (ENABLE_CLONING==1)
	;; check to see if cloning cable is attached
	ld 	a, 0x02
	ld		hl, PBDR
	ioi 	and a, (hl)
	ld 	hl, cloningNow
	jr 	nz, noCloneCable
	ld    (hl), 0x01
   xor   a
   ioi   ld (MMIDR),a     // make sure separate I&D space is off!
	jr    endCloneCheck
noCloneCable:
	ld    (hl), 0x00
endCloneCheck:
#else
	ld 	hl, cloningNow
	ld    (hl), 0x00
#endif

	ld b,SIZESTDIOBUFF
	ld hl,stdioCommBuff
clear_stdio:	
	ld (hl),0
	inc hl
	djnz clear_stdio

dkSetTimer:

	;	initialize baud rate generator
	;	for main clock at 8MHz, the calculation follows:
	;	timer A4 to clock serial port A
	;	timer A5 to clock serial port B
	;	timer A6 to clock serial port C
	;	timer A7 to clock serial port D

	;	make timers tick
	ld 	a, 00000001b
	ioi 	ld (TACSR),a
	ld 	hl,TACSRShadow
	ld    (hl),a

	;	make timer A4 clocked by main clock
	;	disable interrupt
	ld 	a, 00000000b
	ioi 	ld (TACR),a
	ld 	hl,TACRShadow
	ld    (hl),a

	;	Read the time constant for 19200 baud calculated by the coldloader...
	ld		a, (divider19200)
	ld		b, a
checkDoubled:
 ;; is clock doubled?
	ld		a, (GCDRShadow)	; get clock doubler register
	or		a
	jr		z, checkDiv			; if zero, clock not doubled
	sla	b						; if clock doubled, multiply constant by two
checkDiv:
 ;; is clock divided by eight?
	ld		a, (GCSRShadow)	; get global control/status register
	and	018h					; mask off unnecessary bits
	jr		nz, saveFreq		; if nonzero, periph clock not divided by 8
	srl	b
	srl	b						; divide by eight
	srl	b
saveFreq:
	ld		a, b
	ld		(freq_divider), a	; save for later use	

#if (_BIOSBAUD_ == 9600)
	ld		c, a
	sla   c					 	; multiply by two
#endif
#if (_BIOSBAUD_ == 19200)
	ld		c, a					; freq_divider = 19200 divisor
#endif
#if (_BIOSBAUD_ == 38400)
	ld		c, a
	srl   c					 	; divide by two
#endif
#if ( (_BIOSBAUD_ == 57600) || (_BIOSBAUD_ == 115200) )
setDCbaudrate:
  ;; set up proper baud rate for Dynamic C communication by doing some
  ;; 		fixed-point arithmetic to get 57600 rate (= 19200 rate / 3)
	ld		c, 0					; bc = FREQADDR (b = integer part, c = fraction)
	ld		de, 055h				; de = ~1/3
	mul							; multiply it out
	ld		c, l					; keep integer part
	inc	c						; round up since 055h is actually slightly less than 1/3

#if	(_BIOSBAUD_ == 115200)
	srl   c					 	; if 115200 baud wanted, divide by two
#endif
#endif

setBaudRate:
	dec	c						; put divider-1 into timer scaling registers
	ld		a, c
	ioi	ld (TAT4R),a		; save scaledown for 57600 baud
	ld 	hl,TAT4RShadow
	ld    (hl),a
   lret
	
//**************************************************************
// prepare to jump into the debugger

_init_dkLoop::

	call  bioshitwd
	ld 	hl,0
	ld 	(dkControlFlags+commAttn),hl          ; clear tables
	ld 	(dkControlFlags+breakLock),hl
	ld 	(dkControlFlags+watchReq),hl
	ld 	hl,dkControlFlags+keyReq
	ld 	(hl),0ffh      ; clear key request
	xor   a              ; 10-10-95
	ld 	hl,dkControlFlags+hardBreak
	ld    (hl), a        ; 10-10-95, 0 clear hard break flag
	inc   hl
	ld    (hl), a        ; 10-10-95, 0 clear doreset flag
	inc   hl
	ld    (hl), a        ; 10-10-95, 0 showmem
	inc   hl
	ld    (hl), a        ; 10-10-95, 0 spare
	ld 	hl,stepRelay
	ld 	(hl),0c9h      ; ret
	inc   hl
	ld 	(hl),e
	inc   hl
	ld 	(hl),d     		; relay vector

	call  bioshitwd
	xor	a
	ld		(dkRequest),a
	ld		(dkStatusFlags),a
	ld		(dkSendFlags),a
	ipset 0
   lret

#endasm

#asm

; .startup/dkStartup
; code to run each time the program executes
; initializes the stack allocation 
;
dkStartup::	
	pop hl
   jp	(hl)					; jump to old return address
	
#endasm

//#flushlib

#asm

dkEnd::
__xexit::  jp _xexit
#endasm

#flushlib

#asm
_store_ID_Block_Size::
	dw 0xffff
symTab::
	dw		symsize
#endasm

//#flushlib

//	we need to end the symbol table now
#asm
	dw	0		;	indicates end of symbol table
	db	0

symTabEnd::
symsize: equ symTabEnd-symTab-2
#endasm


// include bios C support libraries
#use default.h

//!!!Do NOT insert code between here and #pragma CompileProgram!!!
//#flushlib
#asm
BIOSCodeEnd:
StartUserCode::
#endasm
#pragma CompileProgram

// NOTE: The #use precompile.lib MUST come after the #pragma CompileProgram
#use precompile.lib